#include "ftscu.h"
#include "DrvUART010.h"
#include "timer.h"
#include "interrupt.h"

#define HSIZE_WORD    						0x2
#define HSIZE_HWORD   						0x1
#define HSIZE_HALFWORD   					0x1
#define HSIZE_BYTE    						0x0
#define WORD  								unsigned int
#define HWORD 								unsigned short
#define BYTE  								unsigned char

extern void _uni_wfi(void);

static int ftscu_src(WORD addr, WORD data, BYTE type)
{
    switch( type ){
        case HSIZE_BYTE:
			if(data != *((BYTE *)addr))
                return -1;
            break;
        case HSIZE_HWORD:
            if(data != *((HWORD *)addr))
                return -1;
            break;
        case HSIZE_WORD:
            if(data != *((WORD *)addr))
            	{
            		fLib_printf("src fail ! addr = %X\r\n", addr);
                return -1;
              }
            break;
        default:
            break;
    }
	return 0;
}

static void ftscu_srdata (WORD addr, WORD *data)
{
	*data=*(volatile WORD *) addr;
	return;
}
void ftscu_sw(WORD addr, WORD data, BYTE type)
{
    switch( type ){
        case HSIZE_BYTE:
            *((BYTE  *) addr) = (BYTE) data;
            break;
        case HSIZE_HWORD:
            *((HWORD *) addr) = (HWORD) data;
            break;
        case HSIZE_WORD:
            *((WORD  *) addr) = (WORD) data;
            break;
        default:
            break;
    }
}


//0x100480			HVAD
//0x10100			reset °´¼ü
//0x10000			ÉÏµç
//0x00020000		RTC
wakeup_type uni_get_boot_status(void)
{
	unsigned int value;
	ftscu_srdata(SCU_BASE+SCU_BTUPSTS, &value);
	fLib_printf("bootup status = 0x%x !!\r\n", value);
	if(value & (1 << 9)){
		return WAKEUP_BY_WATCHDOG;
	}
	if(value & (1 << 17)){
		return WAKEUP_BY_RTC;
	}
	if(value & ((1 << 10) | (1 << 7))){
		return WAKEUP_BY_HVAD;
	}	
	if(value & (1 << 8)){
		return WAKEUP_BY_RESET_KEY;
	}

	if(value & (1 << 16)){
		return WAKEUP_BY_POWERON;
	}	
	return WAKEUP_BY_UNKNOWN;
}
int uni_reboot(void)
{
	unsigned int value;
	ftscu_srdata(SCU_BASE+SCU_PWRMOD, &value);
	value |= 1 << 7;
	ftscu_sw(SCU_BASE+SCU_PWRMOD,	value, HSIZE_WORD);
	return 0;
}
void uni_enter_sleep(void)
{
	//======== power on check ========
	// write/read some registers
	//src (SCU_BASE+SCU_BTUPSTS,			0x00010000, HSIZE_WORD);
	ftscu_sw	(SCU_BASE+SCU_BTUPSTS,			0x00010000, HSIZE_WORD);
	//src (SCU_BASE+SCU_BTUPSTS,			0x00000000, HSIZE_WORD);
	
	ftscu_sw	(SCU_BASE+SCU_BTUPCTL,			0x0010ef0f, HSIZE_WORD);
	
	//src (SCU_BASE+SCU_PWRCTL,			rdata,		   HSIZE_WORD);
	ftscu_sw	(SCU_BASE+SCU_BTUPSTS,			0x00000001, HSIZE_WORD);
	/*
	fLib_printf("Turn off PD DSP!!\r\n");
	ftscu_sw	(SCU_BASE+SCU_PWRCTL,			0x01000302, HSIZE_WORD);
	// check power update done
	do{
	   udelay(1000);
	   ftscu_srdata (SCU_BASE+0x048, &rdata);
	   fLib_printf("rdata = 0x%x\r\n", rdata);
	  }while((rdata & 0x00000400) != 0x00000400);
	fLib_printf("PD DSP is OFF!!");
	udelay(10000);
	
  fLib_printf("Turn on PD DSP!!");
  ftscu_sw  (SCU_BASE+SCU_PWRCTL,           0x01000702, HSIZE_WORD);
  // check power update done
  do{
     udelay(1000);
     ftscu_srdata (SCU_BASE+0x90c, &rdata);
    }while((rdata & 0x00000200) != 0x00000200);
  fLib_printf("PD DSP is ON!!");
  udelay(10000);	
	*/
	ftscu_sw	(SCU_BASE+SCU_PWRCTL,			0x00000702, HSIZE_WORD);
	
//#ifdef FTSCU100_PWRUPSEQ_ON
	ftscu_sw	(SCU_BASE+SCU_PWRUPSEQ, 		0x07070302,  HSIZE_WORD);
//#endif
	
	// clear scu state
	ftscu_sw	(SCU_BASE+SCU_STATUS,			0xffffffff, HSIZE_WORD);
	
	//======== enter power down mode and always wakeup by PWRBTN ========
#ifdef FTSCU100_RETMEM_ON
	fLib_printf("Write data to retention memory !!\r\n");
	ftscu_sw	(SCU_BASE+SCU_SCRPAD0,			 0x12345678, HSIZE_WORD);
	ftscu_sw	(SCU_BASE+SCU_SCRPAD1,			 0xffffffff, HSIZE_WORD);
	ftscu_sw	(SCU_BASE+SCU_SCRPAD2,			 0x98abcdef, HSIZE_WORD);
	ftscu_sw	(SCU_BASE+SCU_SCRPAD3,			 0x5a5a5a5a, HSIZE_WORD);
#endif
	// enter power down
	ftscu_sw	(SCU_BASE+SCU_BTUPCTL,			0x0010ec0f, HSIZE_WORD);
	fLib_printf("before _uni_wfi() !\r\n");
	ftscu_sw	(SCU_BASE+SCU_PWRMOD,	  0x00000002, HSIZE_WORD); 
	_uni_wfi();
	while(1)
	{
		fLib_printf("after _uni_wfi() !\r\n");
	}
}

void fcs_isr(UINT32 IntNum)
{
    unsigned int st = 0;
	//unsigned long long end_irq;
	//end_irq = jiffies();
	//fLib_printf("++++enter fcs irq is %d\r\n",end_irq);
	fLib_printf("++++enter fcs irq \r\n");
	st = READ(SCU_BASE+SCU_STATUS);
	WRITE(SCU_BASE+SCU_STATUS,st);//clear irq
}

void uni_fcs(unsigned char PLL_EN,unsigned char CLKIN_MUX,unsigned char PLL_FR,unsigned char PLL_MS,unsigned char PLL_NS)
{
   unsigned int rdata,wdata;
   //unsigned long long start,end;
   
   timer_ctrl(TIMER1, 0, 0); //disable timer

//init irq
 	if(fLib_ConnectInt(SCU_FTSCU100_IRQ, fcs_isr) == 0){
		fLib_printf("Fail to register watchdog_isr \r\n");
		return;
	}
	fLib_SetIntTrig(SCU_FTSCU100_IRQ,0,0);//level,high  

    //======== power on check ========
    ftscu_src (SCU_BASE+SCU_BTUPSTS,     0x00010000, HSIZE_WORD);
    ftscu_sw  (SCU_BASE+SCU_BTUPSTS,     0xffff0000, HSIZE_WORD);
    ftscu_src (SCU_BASE+SCU_BTUPSTS,     0x00000000, HSIZE_WORD);
    ftscu_sw  (SCU_BASE+SCU_BTUPCTL,     0x00030000, HSIZE_WORD);

#ifdef FTSCU100_DEBOUNCE_ON
    rdata = (FTSCU100_PCDCSR_DEF<<28)| (FTSCU100_DEBOUNCE_DEF<<16)| (FTSCU100_PCPWRUP_DEF<<8)| FTSCU100_PCPWRDN_DEF;
#else
    rdata = (FTSCU100_PCDCSR_DEF<<28)| (FTSCU100_PCPWRUP_DEF<<8)| FTSCU100_PCPWRDN_DEF;
#endif
    ftscu_sw (SCU_BASE+SCU_PWRCTL,           rdata,         HSIZE_WORD);

//======== clear scu state ========
    ftscu_sw  (SCU_BASE+SCU_BTUPSTS,          0xffffffff, HSIZE_WORD);
    ftscu_sw  (SCU_BASE+SCU_STATUS,           0xffffffff, HSIZE_WORD);

#if 0
	PLL_EN	   = 0x1;
	CLKIN_MUX  = 0xd;
	PLL_FR	   = 0xdb;
	PLL_MS	   = 0x81;
	PLL_NS	   = 0x2c;
#endif
	
	wdata = (PLL_NS<<24)| (PLL_MS<<16)| (PLL_FR<<8)| (CLKIN_MUX<<4)| PLL_EN;
	ftscu_sw(SCU_BASE+SCU_PLLCTL,	  wdata,		 HSIZE_WORD);
    fLib_printf("INFO: wdata = 0x%x\r\n !!",wdata);
	
	/////////////////////////////////////////////////////////////////////////////
	// Enter FCS1
	/////////////////////////////////////////////////////////////////////////////
	
	fLib_EnableInt(SCU_FTSCU100_IRQ);   	

	ftscu_sw (SCU_BASE+SCU_PWRMOD,       0x40,    HSIZE_WORD);
	
	//start = jiffies();
//For CPU should executes idle instruction (MCR p15, 0, Rd, C7, C0, 4)
    _uni_wfi();
	
	//end = jiffies();
		
	//fLib_printf("***fcs tick is %d\r\n",(end - start));

    //__enable_irq();
    timer_ctrl(TIMER1, 1, 1); //enable timer

    fLib_DisableInt(SCU_FTSCU100_IRQ); 
	
	// check PLL/DLL value
	rdata = (PLL_NS<<24)| (PLL_MS<<16)| (PLL_FR<<8)|(CLKIN_MUX<<4)| 0x2 | PLL_EN;
	ftscu_src (SCU_BASE+SCU_PLLCTL,		rdata,		   HSIZE_WORD);

	fLib_printf("INFO: rdata = 0x%x\r\n !!",rdata);
	
	// check power down and fcs bit be clear
	ftscu_src (SCU_BASE+SCU_PWRMOD,		  0x0,		   HSIZE_WORD);
}

void uni_alarm_test(void)
{
	unsigned int rdata,wdata;
	unsigned int  CENTURY;
    unsigned int  YEAR;
    unsigned int  MONTH;
    unsigned int  DAY;
    unsigned int  WEEKDAY;
    unsigned int  HOUR;
    unsigned int  MINUTE;
    unsigned int  SECOND;
	
	if(fLib_ConnectInt(SCU_FTSCU100_IRQ, fcs_isr) == 0){
		fLib_printf("Fail to register  \r\n");
		return;
	}
	fLib_SetIntTrig(SCU_FTSCU100_IRQ,0,0);//level,high
	fLib_EnableInt(SCU_FTSCU100_IRQ);
	rdata = READ(SCU_BASE+RTC_CTRL);
	fLib_printf("RTC_CTRL value  is  0x%x\r\n",rdata);
	rdata &= ~(0x03);
	ftscu_sw (SCU_BASE+RTC_CTRL, rdata, HSIZE_WORD);
#if 1	
    rdata = READ(SCU_BASE+RTC_CTRL);
	if((rdata & 0x1) == 0x1){
		fLib_printf("+++rdata = 0x%x\r\n",rdata);
		return;	
	}
#endif	
    ftscu_sw (SCU_BASE+SCU_BTUPCTL,0x000200ff, HSIZE_WORD);

    ftscu_sw (SCU_BASE+SCU_INTEN,  0x0001ffff, HSIZE_WORD);
#ifdef FTSCU100_RTC_TRIM_ON
    ftscu_sw (SCU_BASE+SCU_VERID,  FTSCU100_CHIPID, HSIZE_WORD);
  //sw (SCU_BASE+RTC_TRIM, 0x00200240, HSIZE_WORD);
    ftscu_sw(SCU_BASE+RTC_TRIM, 0x00040055, HSIZE_WORD);
#endif	
	CENTURY = 21;
    YEAR    = 19;
    MONTH   = 11;
    DAY     = 28;
    WEEKDAY = 4;
    HOUR    = 10;
    MINUTE  = 31;
    SECOND  = 00;

//set current time
    wdata = (WEEKDAY<<24)| (HOUR<<16)| (MINUTE<<8)| SECOND;
    ftscu_sw (SCU_BASE+RTC_TIME1, wdata, HSIZE_WORD);
    wdata = (CENTURY<<24)| (YEAR<<16)| (MONTH<<8)| DAY;
    ftscu_sw (SCU_BASE+RTC_TIME2, wdata, HSIZE_WORD);

    ftscu_sw (SCU_BASE+RTC_CTRL, 0x000a0001, HSIZE_WORD);
	fLib_printf("RTC alarm verification for specified time !!");

    MONTH   = 11;
    DAY     = 28;
    WEEKDAY = 4;
    HOUR    = 10;
    MINUTE  = 31;
    SECOND  = 05;
    wdata = (WEEKDAY<<24)| (HOUR<<16)| (MINUTE<<8)| SECOND;
    ftscu_sw(SCU_BASE+RTC_ALMTIME1, wdata, HSIZE_WORD);

    wdata = (MONTH<<8)| DAY;
    ftscu_sw (SCU_BASE+RTC_ALMTIME2, wdata, HSIZE_WORD);
	
    ftscu_sw (SCU_BASE+RTC_CTRL, 0x000a0003, HSIZE_WORD);
	
	//check Alarm Enable
   do{
     rdata = READ(SCU_BASE+RTC_CTRL);
   }while((rdata & 0x100) != 0x100);
   
   // enter power down
   fLib_printf("Enter softoff for RTC wakeup test!!");
   ftscu_sw  (SCU_BASE+SCU_PWRMOD,     0x00000002, HSIZE_WORD); 
   _uni_wfi();  	
} 

